package com.classloader.simulate;

import com.encryption.demo.EncryptionUtils;
import org.apache.commons.lang.StringUtils;

import java.io.File;
import java.io.FileInputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * @author hong
 * @version 1.0
 * @description: 模似打破双亲委派机制
 * @date 2022/4/16 18:50
 */
public class SimulateTomcatClassLoader  {

    static class MySelfClassLoader extends ClassLoader{
        /**
         * 类路劲
         **/
        private String classPath;

        public MySelfClassLoader(String classPath) {
            this.classPath = classPath;
        }

        private byte[] loadByClassName(String className) throws Exception {
            if (StringUtils.isEmpty(className)) {
                throw new Exception("类名不能为空！");
            }
            //替换路劲格式
            className = className.replaceAll("\\.", "/");
            //获取文件信息
            FileInputStream fis = new FileInputStream(classPath + "/" + className + ".class");
            //获取长度
            int len = fis.available();
            //文件信息
            byte[] data = new byte[len];
            //读写文件信息
            fis.read(data);
            fis.close();
            return data;

        }

        @Override
        protected Class<?> findClass(String name) throws ClassNotFoundException {
            try {
                byte[] data = loadByClassName(name);
                return defineClass(name, data, 0, data.length);
            } catch (Exception e) {
                e.printStackTrace();
                throw new ClassNotFoundException();
            }
        }

        /**
         * 重写类加载方法，在这里打破双亲委派
         * @param name
         * @param resolve
         * @return
         * @throws ClassNotFoundException
         */
        @Override
        protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
            synchronized (getClassLoadingLock(name)) {
                // First, check if the class has already been loaded
                Class<?> c = findLoadedClass(name);
//            if (c == null) {
//                long t0 = System.nanoTime();
//                try {
//                    if (parent != null) {
//                        c = parent.loadClass(name, false);
//                    } else {
//                        c = findBootstrapClassOrNull(name);
//                    }
//                } catch (ClassNotFoundException e) {
//                    // ClassNotFoundException thrown if class not found
//                    // from the non-null parent class loader
//                }


                if (c == null) {
                    // If still not found, then invoke findClass in order
                    // to find the class.
                    long t1 = System.nanoTime();
                    //这里重写逻辑 如果不是自定义类开头就用默认类加载器，如果是就有自定义类加载器加载
                    if(!name.startsWith("com.classloader")){
                        c = this.getParent().loadClass(name);
                    }else{
                        c = findClass(name);
                    }

                    // this is the defining class loader; record the stats
//                    sun.misc.PerfCounter.getParentDelegationTime().addTime(t1);
                    sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                    sun.misc.PerfCounter.getFindClasses().increment();
                }
//            }
                if (resolve) {
                    resolveClass(c);
                }
                return c;
            }
        }
    }


    public void test(){
        System.out.println("测试类！");
    }

    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        //获取项目路劲
        File file = new File(EncryptionUtils.class.getResource("/").getPath());
        MySelfClassLoader mySelfClaasLoader = new MySelfClassLoader(file.getPath());
        Class<?> loadClass = mySelfClaasLoader.loadClass("com.classloader.simulate.SimulateTomcatClassLoader");
        //获取实例对象
        Object obj = loadClass.newInstance();
        //获取方法列表
        Method[] declaredMethods = loadClass.getDeclaredMethods();
        System.out.println(declaredMethods);
        //获取方法
        Method method = loadClass.getMethod("test", null);
        method.invoke(obj,null);
        System.out.println(loadClass.getClassLoader().getClass().getName());;




    }
}
